package com.lancoo.ccas52.arrangecourse.AlgDataSource.dataprocess.Impl;

import com.lancoo.ccas52.arrangecourse.AlgDataSource.baseentity.College;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.baseentity.Course;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.baseentity.MajorGrade;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.baseentity.Teacher;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.common.Constants;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.dataprocess.CourseDataService;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.dataprocess.MajorGradeDataService;
import com.lancoo.ccas52.arrangecourse.AlgDataSource.dataprocess.TeachingClassDataService;
import com.lancoo.ccas52.pojo.dto.ArrangeCourseRuleDto;
import com.lancoo.ccas52.pojo.dto.ArrangePeriod;
import com.lancoo.ccas52.pojo.dto.ArrangeTeacherRuleDto;
import com.lancoo.ccas52.pojo.dto.ArrangeTeachingClassDto;
import com.lancoo.ccas52.pojo.vo.Campus;

import java.util.*;

/**
 * @Description 教学版信息生成
 * @Author Fortysun
 * @Date 2023/4/11 14:35
 **/
public class TeachingClassDataServiceImpl extends PublicDataService implements TeachingClassDataService {
    /**课程数据处理类**/
    private CourseDataService courseDataService;
    /**专业年级信息处理类**/
    private MajorGradeDataService majorGradeDataService;

    private HashMap<String, List<ArrangeTeachingClassDto>> teachingClassMap;

    public TeachingClassDataServiceImpl() {
        //初始化
        majorGradeDataService = new MajorGradeDataServiceImpl();

        courseDataService = new CourseDataServiceImpl(majorGradeDataService.getCollegeList());

        teachingClassMap = initTeachingClassMap();
    }

    /**
     * 从每个院系选几个教师，设置禁排、一定排
     * @param timeslotList 课时信息列表
     * @return
     */
    @Override
    public List<ArrangeTeacherRuleDto> getTeacherRuleList(List<ArrangePeriod> timeslotList) {
        //用来存储需要设置禁排的教师
        List<Teacher> teacherList = new ArrayList<>();

        HashMap<String, List<Teacher>> teacherMap = courseDataService.getTeacherMap();
        teacherMap.forEach((key, value) ->{
            int i = 0;
            for (Teacher teacher : value) {
                //从中选出10个教师
                if (i < Constants.RULE_TEACHER_NUM) {
                    teacherList.add(teacher);
                }
                i++;
            }
        });

        return generateTeacherRuleList(teacherList, timeslotList);
    }

    /**
     * 生成教师规则
     * @param teacherList 需要生成规则的教师列表
     * @param timeslotList 课时信息列表
     * @return
     */
    private List<ArrangeTeacherRuleDto> generateTeacherRuleList(List<Teacher> teacherList,
                                                                List<ArrangePeriod> timeslotList) {
        List<ArrangeTeacherRuleDto> teacherRuleList = new ArrayList<>();

        for (int i = 0; i < teacherList.size(); i++) {
            //将生成的教师规则，加入列表
            teacherRuleList.add(new ArrangeTeacherRuleDto(
                    teacherList.get(i).getTeacherId(),
                    timeslotList.get(i%timeslotList.size()).getTimeCode(),
                    (i%2==0?0:2)
            ));
        }

        return teacherRuleList;
    }

    /**
     * 判断当前的教学班是否已经存在
     * 因为当前的教学班列表，是按照不同的授课类型为粒度，去进行存储的
     * 所以会存在重复的教学班数据
     * @param teachingClass 比较的教学班
     * @param ruleTeachingClassList 当前最新的教学班列表
     * @return
     */
    private boolean isInRuleTeachingClassList(ArrangeTeachingClassDto teachingClass,
                                              List<ArrangeTeachingClassDto> ruleTeachingClassList) {
        for (ArrangeTeachingClassDto ruleTeachingClass : ruleTeachingClassList) {
            //如果教学班相同，说明存在相同的教学班
            if(teachingClass.getTeachingClassId().equals(
                    ruleTeachingClass.getTeachingClassId()))
                return true;
        }
        return false;
    }

    /**
     * 从每个院系选几个课程，设置禁排
     * @param timeslotList 课时信息列表
     * @return
     */
    @Override
    public List<ArrangeCourseRuleDto> getCourseRuleList(List<ArrangePeriod> timeslotList) {
        //存储需要设置禁排的课程
        List<ArrangeTeachingClassDto> ruleTeachingClassList = new ArrayList<>();
        //获取校区列表信息
        List<Campus> campusList = majorGradeDataService.getCampusList();

        for (Campus campus : campusList) {
            ruleTeachingClassList.addAll(getCampusCourseRuleList(teachingClassMap.get(campus.getCampusId())));
        }

        return generateCourseRuleList(ruleTeachingClassList, timeslotList);
    }

    //获取用于设置，教学班禁排的，教学班列表信息
    private List<ArrangeTeachingClassDto> getCampusCourseRuleList(List<ArrangeTeachingClassDto> campusTeachingClassList) {

        //存储需要设置禁排的课程
        List<ArrangeTeachingClassDto> campusRuleTeachingClassList = new ArrayList<>();
        //统计每个校区的30个教学班
        int count = 0;
        for (ArrangeTeachingClassDto teachingClass : campusTeachingClassList) {
            //取够了足够的数据，就取下一个学院的数据
            if (count >= Constants.COMPUS_COURSE_RULE_NUM) {
                break;
            }

            if (!isInRuleTeachingClassList(teachingClass, campusRuleTeachingClassList)) {
                campusRuleTeachingClassList.add(teachingClass);
                count++;
            }
        }
        return campusRuleTeachingClassList;
    }

    /**
     * 生成课程禁排的规则列表
     * @param ruleTeachingClassList 教学班列表
     * @param timeslotList 课时信息列表
     * @return
     */
    private List<ArrangeCourseRuleDto> generateCourseRuleList(List<ArrangeTeachingClassDto> ruleTeachingClassList,
                                                              List<ArrangePeriod> timeslotList) {
        List<ArrangeCourseRuleDto> courseRuleList = new ArrayList<>();

        for (int i = 0; i < ruleTeachingClassList.size(); i++) {
            ArrangeTeachingClassDto teachingClass = ruleTeachingClassList.get(i);
            //将生成的教师规则，加入列表
            courseRuleList.add(new ArrangeCourseRuleDto(
                    teachingClass.getCourseId(),
                    timeslotList.get(i%timeslotList.size()).getTimeCode(),
                    teachingClass.getTeachingClassId(),2
            ));
        }

        return courseRuleList;
    }

    /**
     * 获取所有的教学班信息列表
     * @return
     */
    @Override
    public HashMap<String, List<ArrangeTeachingClassDto>> getTeachingClassMap() {
        return this.teachingClassMap;
    }

    /**
     * 返回校区信息
     * @return
     */
    @Override
    public List<Campus> getCampusList() {
        return this.majorGradeDataService.getCampusList();
    }

    /**
     * 按校区生成教学班map信息
     * @param allTeachingClassList 教学班列表；
     * @return
     */
    private HashMap<String, List<ArrangeTeachingClassDto>> generateTeachingClassMap(
            List<ArrangeTeachingClassDto> allTeachingClassList) {
        //获取校区列表信息
        List<Campus> campusList = majorGradeDataService.getCampusList();
        //存储不同校区的教学班列表信息
        HashMap<String, List<ArrangeTeachingClassDto>> classMap = new HashMap<>();

        for (Campus campus : campusList) {
            //用于保存指定校区的教学班信息；
            List<ArrangeTeachingClassDto> teachingClassList = new ArrayList<>();
            for (ArrangeTeachingClassDto teachingClass : allTeachingClassList) {
                if (campus.getCampusId().equals(teachingClass.getCampusId())) {
                    teachingClassList.add(teachingClass);
                }
            }
            classMap.put(campus.getCampusId(), teachingClassList);
        }

        return classMap;
    }

    /**
     * 初始化生成所有的教学班信息列表
     * @return
     */
    private HashMap<String, List<ArrangeTeachingClassDto>> initTeachingClassMap() {
        //计算不同授课类型的教学班总数
        int teachingClassCount = Constants.COLLEGE_NUM*//院系数
                Constants.COLLEGE_COURSE_NUM *//每个院系的课程数
                Constants.COURSE_TEACHING_CLASS_NUM*//每个课程的教学班数量
                Constants.COURSE_TYPE_NUM;//每个课程的授课种类
        HashMap<Integer, List<Integer>> hourTypeMap = initTeachingClassHourType(teachingClassCount);
        //用来初始化连上节次的列表，设置了连上节次出现的分布
        List<Integer> connectSectionList = initConnectSection();
        //获取院系信息
        List<College> collegeList = majorGradeDataService.getCollegeList();

                //定义返回的列表信息
        List<ArrangeTeachingClassDto> allTeachingClassList = new ArrayList<>();
        int index =0;
        for (College college : collegeList) {
            //获取指定院系的教学班信息
            List<ArrangeTeachingClassDto> teachingClassList = getCollegeTeachingClassList(
                    index,
                    majorGradeDataService.getMajorGradeMap().get(college.getCollegeId()),
                    courseDataService.getCourseMap().get(college.getCollegeId()),
                    hourTypeMap,
                    connectSectionList
            );

            allTeachingClassList.addAll(teachingClassList);
            index ++;
        }

        return generateTeachingClassMap(allTeachingClassList);
    }

    /**
     * 获取指定院系的，教学班列表信息
     * @param majorGradeList 专业年级列表
     * @param courseList 课程列表
     * @return
     */
    private List<ArrangeTeachingClassDto> getCollegeTeachingClassList(
            int collegeIndex,
            List<MajorGrade> majorGradeList,
            List<Course> courseList,
            HashMap<Integer, List<Integer>> hourTypeMap,
            List<Integer> connectSectionList) {
        List<ArrangeTeachingClassDto> allTeachingClassList = new ArrayList<>();

        int j = 0;

        List<ArrangeTeachingClassDto> teachingClassList = null;
        for (Course course : courseList) {
            teachingClassList = getCourseTeachingClassList(
                    collegeIndex*courseList.size() + j,
                    majorGradeList.get(j%majorGradeList.size()),
                    course,
                    hourTypeMap,
                    connectSectionList);
            allTeachingClassList.addAll(teachingClassList);
            j++;
        }


        return allTeachingClassList;
    }

    /**
     * 生成专业年级对应的教学班列表
     * @param index 对应的专业和课程
     * @param majorGrade 专业年级对象
     * @param course 课程
     * @return
     */
    private List<ArrangeTeachingClassDto> getCourseTeachingClassList(int index,
                                                     MajorGrade majorGrade,
                                                     Course course,
                                                     HashMap<Integer, List<Integer>> hourTypeMap,
                                                     List<Integer> connectSectionList) {

        List<ArrangeTeachingClassDto> teachingClassList = new ArrayList<>();
        //每个课程生成几个教学班
        for (int i = 0; i< Constants.COURSE_TEACHING_CLASS_NUM; i++){
            //获取分配给这个教学班的教师；
            String teachers = getTeachingClassTeachers(i, course.getTeacherList());
            //拆分出教师id和教师名称字符串；
            String[] teacherArr = teachers.split("&");
            //当前每个课程的教学班数量，跟专业年级对应的行政班数量是相等的，所以可以直接指定
            //TODO 如果两者的数量不一样，需要单独封装方法，进行处理；
            String studentIds = majorGrade.getStudentIdsList().get(i);
            //每个课程有不同的授课方式类型，根据包含的授课方式类型，去生成教学班
            for (int j = 0; j < course.getCourseTypeNum(); j++){
                ArrangeTeachingClassDto teachingClass = new ArrangeTeachingClassDto();
                int idNo = index*Constants.COURSE_TEACHING_CLASS_NUM + i;
                teachingClass.setTeachingClassId((long)(idNo+1));
                teachingClass.setTeachingClassName(course.getCourseName() + majorGrade.getGradeName()
                        + (i+1) + "班");
                teachingClass.setTeachingClassType(0);//无需选课
                teachingClass.setCampusId(majorGrade.getCampusId());
                teachingClass.setCampusName(majorGrade.getCampusName());
                teachingClass.setCourseId(course.getCourseId());
                teachingClass.setCourseName(course.getCourseName());
                teachingClass.setFlag(1);//课程
                int hourType = hourTypeMap.get(idNo).get(j);
                teachingClass.setHourType(hourType);
                teachingClass.setRoomType(getRoomType(hourType));
                teachingClass.setStudentIds(studentIds);
                teachingClass.setStudentNumber(Constants.CLASS_STUDENT_NUM+i);
                teachingClass.setTeacherIds(teacherArr[0]);
                teachingClass.setTeacherNames(teacherArr[1]);
                teachingClass.setWeek(course.getWeek());
                teachingClass.setWeekNum(course.getWeekNum());
                //连上节次，1~4
                teachingClass.setConnectSection(connectSectionList.get(idNo));
//                teachingClass.setUniqueShiftSign(1);
                if (connectSectionList.get(idNo).equals(2)) {
                    teachingClass.setConnectNumber(2);
                } else if (connectSectionList.get(idNo).equals(1)) {
                    teachingClass.setConnectNumber(0);
                } else {
                    teachingClass.setConnectNumber(1);
                }
                teachingClassList.add(teachingClass);
            }
        }

        return teachingClassList;
    }


    /**
     * 根据生成的教学班数量，以及课程分配的教师，对生成分配给教学班的教师
     * @param index 当前分配的是这个课程的第几个班级
     * @param teacherList 教师信息列表
     * @return
     */
    private String getTeachingClassTeachers(int index, List<Teacher> teacherList) {
        String retStr = "";
        String teacherIds = "";
        String teacherNames = "";

        int teacherNum = teacherList.size();
        //如果教师数量，大于教学班的数量，那么存在一个教学班，分配多位教师的情况
        if (teacherNum > Constants.COURSE_TEACHING_CLASS_NUM) {
            //每个教学班平均分配的教师数量
            int teachingClassTeacherNum = teacherNum/Constants.COURSE_TEACHING_CLASS_NUM;
            int dValue = teacherNum - Constants.COURSE_TEACHING_CLASS_NUM*teachingClassTeacherNum;
            for (int i = 0; i < teacherNum; i++) {
                //前面dValue个教学班需要比平均值，多分配一位教师
                if (index < dValue) {
                    for (int j = 0; j < teachingClassTeacherNum + 1; j++) {
                        teacherIds += teacherList.get((index +j)%teacherNum).getTeacherId() + ",";
                        teacherNames += teacherList.get((index +j)%teacherNum).getTeacherName() + ",";
                    }
                } else {
                    //按照平均值分配
                    for (int j = 0; j < teachingClassTeacherNum; j++) {
                        teacherIds += teacherList.get((index +j)%teacherNum).getTeacherId() + ",";
                        teacherNames += teacherList.get((index +j)%teacherNum).getTeacherName() + ",";
                    }
                }
            }

            //去掉末尾的逗号
            teacherIds = teacherIds.substring(0, teacherIds.length()-1);
            teacherNames = teacherNames.substring(0, teacherNames.length()-1);
        } else {
            //如果教师数量，现有教学班的数量，那么每个教学班就分配一位教师
            teacherIds = teacherList.get(index%teacherNum).getTeacherId()+"";
            teacherNames = teacherList.get(index%teacherNum).getTeacherName();
        }
        //将教师id和姓名字符串，通过竖线进行分隔，并返回
        retStr = teacherIds+"&"+teacherNames;

        return retStr;
    }
}
